package com.ovopark.firecar.service;


import android.app.Notification;
import android.content.Intent;
import android.os.Handler;
import android.os.IBinder;
import android.text.TextUtils;
import android.util.Log;

import androidx.annotation.Nullable;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.ovopark.firecar.bean.GetMessageListObj;
import com.ovopark.firecar.bean.WSMessageResult;
import com.ovopark.firecar.common.Constants;
import com.ovopark.firecar.event.WebSocketServiceEvent;
import com.ovopark.firecar.helper.NetHeaderHelper;
import com.ovopark.firecar.utils.NetUtils;
import com.ovopark.firecar.utils.PushUtils;
import com.ovopark.firecar.utils.ServiceUtils;
import com.ovopark.firecar.utils.StringUtils;
import com.ovopark.event.websocket.WebSocketMessageEvent;
import com.ovopark.event.websocket.WebSocketPushEvent;
import com.ovopark.event.websocket.WebSocketStatusChangeEvent;
import com.ovopark.service.BaseNotificationService;
import com.ovopark.websocket.JavaWebSocket;

import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;
import org.java_websocket.handshake.ServerHandshake;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import io.reactivex.Flowable;
import io.reactivex.annotations.NonNull;
import io.reactivex.disposables.Disposable;
import io.reactivex.functions.Consumer;
import io.reactivex.functions.Predicate;

/**
 * Created by cz on 2017/9/25.
 */

public class WebSocketService extends BaseNotificationService {

    private String TAG = WebSocketService.class.getSimpleName();

    private JavaWebSocket client;

    private String token;
    private Disposable disposable;
    private Disposable pushDisposable;

    private Map<String, String> httpHeaders;
    private String url;
    private int reconnectCount = 0;
    private final static int MAX_RECONNECT = 5;
    private final static int RECONNECT_DELAY = 1000;
    private Handler mHandler = new Handler();

    private int reconnectDelay = 1000;


    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    @Override
    public void onCreate() {
        super.onCreate();
        Log.d(TAG, "WebSocketService is running");
        if (!EventBus.getDefault().isRegistered(this)) {
            EventBus.getDefault().register(this);
        }

        startForeground(Constants.NotificationIds.FLOAT_VIDEO_ID,new Notification());

    }

    @Override
    public void onServiceStartCommand(Intent intent, int flags, int startId) {
//        token = getUserToken();
        token = "4c81e19fac8f41e3a4908dce6e7ddb35";
        initMessage();
        autoMessage();
    }

    @Override
    public void onDestroy() {

        if (EventBus.getDefault().isRegistered(this)) {
            EventBus.getDefault().unregister(this);
        }
        if (client != null) {
            client.close();
            client = null;
        }
        if (disposable != null && !disposable.isDisposed()) {
            disposable.dispose();
        }
        if (reconnectRunnable != null) {
            mHandler.removeCallbacks(reconnectRunnable);
        }
        if (reconnectNewRunnable != null) {
            mHandler.removeCallbacks(reconnectNewRunnable);
        }
        Log.d(TAG, "WebSocketService is destroyed");
        super.onDestroy();
    }

    @Override
    public int getServiceChannelId() {
        return Constants.NotificationIds.WEBSOCKET_ID;
    }

    @Subscribe(threadMode = ThreadMode.MAIN)
    public void onEventMainThread(WebSocketServiceEvent event) {
        if (null != event) {
            if (event.isStart()) {
                if (client != null) {
                    client.close();
                    client = null;
                }

//                token = getUserToken();
//                token = "asdasfqqwf";

                autoMessage();
            } else {
                if (client != null) {
                    client.close();
                    client = null;
                }

                if (disposable != null && !disposable.isDisposed()) {
                    disposable.dispose();
                }
            }
        }
    }

    @Subscribe(threadMode = ThreadMode.MAIN)
    public void onEventMainThread(WebSocketPushEvent event) {
        if (event != null && !StringUtils.isEmpty(event.getMsg())) {
            sendMessage(event.getMsg());
        }
    }

    private void sendMessage(final String message) {
        pushDisposable = Flowable.intervalRange(0, 30, 0, 1, TimeUnit.SECONDS)
                .onBackpressureDrop()
                .filter(new Predicate<Long>() {
                    @Override
                    public boolean test(@NonNull Long aLong) throws Exception {
                        return client != null && client.isOpen();
                    }
                }).subscribe(new Consumer<Long>() {
                    @Override
                    public void accept(@NonNull Long aLong) throws Exception {
                        try {
                            Log.e(TAG, message);
                            client.send(message);
                            pushDisposable.dispose();
                        } catch (Exception e) {

                        }
                    }
                });
    }

    private void initMessage() {
        httpHeaders = new HashMap<>();
        //httpHeaders.put("authenticator", token + " " + "Android" + " " + BuildConfig.VERSION_NAME);
        httpHeaders.put("Ovo-Authorization", token + NetHeaderHelper.getRegisterInfo());
        //url = DataManager.getInstance().getBaseUrl().replace("http://", "ws://") + "websocket";
        //动态获取socket url
//        url = NewAddressUtils.getNewServerUrl(NewAddressUtils.SERVER_WEBSOCKET);
        url = "ws://121.43.123.76:8088/shopweb-websocket/websocket";
    }

    private void autoMessage() {
        if (StringUtils.isBlank(token)) {
            this.stopSelf();
            return;
        }

        if (StringUtils.isBlank(url)) {
//            getSeverAddress();
            return;
        }
        if (client != null) {
            client.close();
            client = null;
        }
        client = JavaWebSocket.getInstance(url, httpHeaders, new JavaWebSocket.OnGetWebSocketCallback() {
            @Override
            public void onOpen(ServerHandshake serverHandshake) {
                Log.d(TAG, "############ WebSocketClient connect ############");
                sendMsgForWS();
                reconnectCount = 0;
            }

            @Override
            public void onMessage(String message) {
                Log.d(TAG, message);
//                if (!StringUtils.isBlank(message)) {
                WSMessageResult result;
//                    if (message.contains("\"msgType\":\"9000\"")) {
//                        result = getResult(JSON.parseObject(message));
//                    } else {
                result = JSON.parseObject(message, WSMessageResult.class);
                WebSocketMessageEvent event = new WebSocketMessageEvent(result);
                event.setMsg(message);
                EventBus.getDefault().post(event);


//            }
            }

            @Override
            public void onClose(int i, String s, boolean b) {
                Log.d(TAG, "############ WebSocketClient close ############");
                if (client != null && PushUtils.isAppRunning(getApplicationContext()) &&
                        ServiceUtils.isServiceWorking(getApplicationContext(), WebSocketService.class)) {
                    if (!NetUtils.isNetworkConnected(getApplicationContext())) {
                        client = null;
                        stopSelf();
                        return;
                    }
                    client = null;

                    if (reconnectCount == MAX_RECONNECT) {
                        EventBus.getDefault().post(new WebSocketStatusChangeEvent(reconnectCount, true));
                    }
                    reconnectCount++;
                    if (reconnectRunnable != null) {
                        mHandler.removeCallbacks(reconnectRunnable);
                        mHandler.postDelayed(reconnectRunnable, RECONNECT_DELAY);
                    }
                } else {
                    client = null;
                    stopSelf();
                }
            }

            @Override
            public void onError(Exception e) {
                Log.d(TAG, e.getMessage());
            }
        });
        client.connect();
    }


    /**
     * 一分钟一次心跳发送
     */
    private void sendMsgForWS() {
        disposable = Flowable.interval(1, TimeUnit.MINUTES)
                .onBackpressureDrop()
                .subscribe(new Consumer<Long>() {
                    @Override
                    public void accept(@NonNull Long aLong) throws Exception {
                        try {
                            if (TextUtils.isEmpty(token) && client != null && client.isOpen()) {
                                if (PushUtils.isAppRunning(getApplicationContext())) {
                                    Log.d(TAG, "############ WebSocketClient Send SYNC ############");
                                    client.send("SYNC");
                                } else {
                                    WebSocketService.this.stopSelf();
                                }
                            }
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
                });
    }

//    @Nullable
//    private String getUserToken() {
//        try {
//            return LoginUtils.getCachedUserToken();
//        } catch (Exception e) {
//            e.printStackTrace();
//        }
//        return null;
//    }

    private Runnable reconnectRunnable = new Runnable() {
        @Override
        public void run() {
//            EventBus.getDefault().post(new WebSocketStatusChangeEvent(reconnectCount, false));
            autoMessage();
        }
    };

//    private void getSeverAddress() {
//        CommonApi.getInstance().getServerUrl(new OkHttpRequestParams(), new OnResponseCallback2<ServerUrlModel>() {
//            @Override
//            public void onSuccess(ServerUrlModel serverUrlModel) {
//                super.onSuccess(serverUrlModel);
//                try {
//                    if (serverUrlModel != null) {
//                        Log.i(TAG,"set dev supportt server: "+JSONObject.toJSONString(serverUrlModel));
//                        SharedPreferencesUtils.getInstance(SERVER_ADDR).setParam(getApplicationContext(),
//                                Constants.Prefs.SERVER_NEW_ADDR_KEY, JSONObject.toJSONString(serverUrlModel));
//
//                        url = serverUrlModel.getWebsocketServerUrl();
//                        if (StringUtils.isBlank(url)) {
//                            WebSocketService.this.stopSelf();
//                        }
////                        autoMessage();
//                    } else {
//                        retryGetAddress();
//                    }
//                } catch (Exception e) {
//                    e.printStackTrace();
//                    retryGetAddress();
//                }
//            }
//
//            @Override
//            public void onSuccessError(String resultCode, String errorMessage) {
//                super.onSuccessError(resultCode, errorMessage);
//                retryGetAddress();
//            }
//
//            @Override
//            public void onFailure(int errorCode, String msg) {
//                super.onFailure(errorCode, msg);
//                retryGetAddress();
//            }
//        });
//    }

    private void retryGetAddress() {
        if (reconnectDelay <= RECONNECT_DELAY * 10) {
            reconnectDelay = reconnectDelay + RECONNECT_DELAY;
        }
        if (reconnectNewRunnable != null) {
            mHandler.removeCallbacks(reconnectNewRunnable);
            mHandler.postDelayed(reconnectNewRunnable, reconnectDelay);
        }
    }

    private Runnable reconnectNewRunnable = new Runnable() {
        @Override
        public void run() {
            EventBus.getDefault().post(new WebSocketStatusChangeEvent(reconnectCount, false));
            autoMessage();
        }
    };

    private WSMessageResult getResult(JSONObject jsonObject) {
        WSMessageResult wsMessageResult = new WSMessageResult();
        wsMessageResult.setDataType(jsonObject.getString("dataType"));
        wsMessageResult.setMsgType(jsonObject.getInteger("msgType") == null ? 0 : jsonObject.getInteger("msgType"));
        wsMessageResult.setMsg(getListObj(jsonObject.getJSONObject("msg")));
        wsMessageResult.setSrcSessionId(jsonObject.getString("srcSessionId"));
        wsMessageResult.setTargetSessionId(jsonObject.getString("targetSessionId"));
        return wsMessageResult;
    }

    private GetMessageListObj getListObj(JSONObject jsonObject) {
        GetMessageListObj getMessageListObj = new GetMessageListObj();
        getMessageListObj.setContent((jsonObject.getJSONObject("content")).toJSONString());
        getMessageListObj.setCustomers((jsonObject.getJSONObject("customers")).toJSONString());
        getMessageListObj.setCreateTime(jsonObject.getString("createTime"));
        getMessageListObj.setDescription(jsonObject.getString("description"));
        getMessageListObj.setId(jsonObject.getString("id"));
        getMessageListObj.setObjectId(jsonObject.getInteger("objectId") == null ? 0 : jsonObject.getInteger("objectId"));
        getMessageListObj.setObjectIds(jsonObject.getString("objectIds"));
        getMessageListObj.setObjectType(jsonObject.getString("objectType"));
        getMessageListObj.setObjectURL(jsonObject.getString("objectURL"));
        getMessageListObj.setOption(jsonObject.getString("option"));
        getMessageListObj.setSrcUserId(jsonObject.getString("srcUserId"));
        getMessageListObj.setStatus(jsonObject.getString("status"));
        getMessageListObj.setTargetUserId(jsonObject.getInteger("targetUserId"));
        getMessageListObj.setMessageType(jsonObject.getInteger("messageType") == null ? -1 : jsonObject.getInteger("messageType"));
        return getMessageListObj;
    }

}
